//-------------------------------------------------------------------
//	Copyright (c) 2010-2012 Zhirnov Andrey
//	This file is part of the "UXGEN" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#ifndef _UX_POST_PROCESS_H
#define _UX_POST_PROCESS_H

#include "IPostProcess.h"
#include "PostProcessTypes.h"
#include "../Systems/Render/AllRenderUtils.h"

namespace Engine
{
namespace Resources
{

	//
	// Post Process Base
	//

	class _EXPORT_ CPostProcessBase : public IPostProcessBase
	{
		friend class  CPostProcess;
		friend struct Engine::TMetaDataInitializer;

	protected:
		struct TArrayRange
		{
			uint	uFirst,
					uCount;
			///
			TArrayRange(): uFirst(0), uCount(0) {}
			TArrayRange(uint first, uint count): uFirst(first), uCount(count) {}
			bool Empty()	const	{ return uCount == 0; }
			uint Count()	const	{ return uCount; }
			uint First()	const	{ return uFirst; }
		};


		struct CPostProcessPass
		{
			TArrayRange					_sSrcTextures,
										_sRenderTargets,
										_sProgramData;
			CBaseProgramShellPtr		_pProgram;
			string						_sName;
			TGLRenderState				_sRenderState;
			frect						_sViewport;
			bool						_bChangeRS;
			///
			CPostProcessPass(): _sViewport(0.f, 0.f, 1.f, 1.f), _bChangeRS(false) {}
		};


		class CPPTexManager : public CEngBaseObject
		{
		public:
			struct _TTexInfo
			{
				const CTexturePtr*	pTexture;
				string				sName;
				///
				_TTexInfo(): pTexture(nullptr), sName() {}
				_TTexInfo(const CTexturePtr *tex, const string &name): pTexture(tex), sName(name) {}
			};

			struct _TResTex
			{
				const CTexturePtr*	pTexture;
				e_pp_texture::type	eType;
				///
				_TResTex():	pTexture(nullptr), eType(e_pp_texture::UNKNOWN) {}
				_TResTex(const CTexturePtr *tex, e_pp_texture::type type): pTexture(tex), eType(type) {}
			};

			typedef array< _TResTex >		restex_array_t;

			array< _TTexInfo >				_aTextures;			// temp
			buffer< TPostProcessTexture >	_aSrcTextures;		// input
			buffer< CTexturePtr >			_aCreatedTextures;	// render targets & loaded textures
			restex_array_t					_aResultRT;			// output

			array< TBindTexture >			_aInputTextures;	// pp passes input
			array< TPPRenderTarget >		_aRenderTargets;	// pp passes output
			array< TProgData >				_aProgramData;		// pp passes prog data

		public:
			CPPTexManager();
			~CPPTexManager();

			void Replace(CPPTexManager &cTexMan);

			bool CreateRT(const TRenderTarget &sRT, uint &uPos, const array<TInputTexture> &aOutput);
			bool GetTexture(const string &sName, const CTexturePtr *&pTex) const;
			void Clear();

			// CEngBaseObject //
			void Release();
		};

	protected:
		array< CPostProcessPass *>	_aPasses;
		array< CPostProcessPass *>	_aPostProcessPasses;
		uint32_array_t				_aPassTracks;
		CPPTexManager				_cTexManager;
		e_post_process::type		_ePPType;
		bool						_bReady;

	private:
		bool _CreatePass(const TPPPass &sPass);
		bool _BindPass(CPostProcessPass *pPass, FBO_t *pFBO, bool bToScreen, bool bLastPass);

		bool _CheckIndex(uint uIndex)						{ return (uIndex<<1) < _aPassTracks.Count(); }

		static bool _s_InitPostProcess();
		static bool _s_IsInitMetaData();
		static CMetaClass	*_s_GetPostProcess();

	protected:
		CPostProcessBase(const char *pFileName);
		virtual ~CPostProcessBase();
		virtual bool _Replace(CResource *pRes);
		virtual bool _Load(IFilePtr pFile, uint uSize);
		virtual bool _Save(IFilePtr pFile);
		virtual bool _Reload(IFilePtr pFile, bool bRecursive);

		bool _Create(const TPostProcess &sInit);

	public:
		//virtual bool  Compare(CResource *pRes);
		virtual void Destroy();
		
		virtual bool				IsValid()		const	{ return !_aPostProcessPasses.Empty(); }
		virtual e_resource::type		GetType()		const	{ return e_resource::POST_PROCESS; }

		bool CheckStatus();
		bool Process(uint uIndex, bool bToScreen);

		
		// IPostProcessBase //
		virtual bool GetPostProcess(IPostProcessPtr &pPostProcess);

		virtual e_post_process::type GetPostProcessType() const { return _ePPType; }

		static IPostProcessBasePtr s_CreatePostProcessBase(const char *pFileName);
	};



	//
	// Post Process
	//

	class _EXPORT_ CPostProcess : public IPostProcess
	{
	protected:
		typedef CRefCounter< CPostProcessBase, CReferenced, TRefCountStrategy< CReferenced > >	CPostProcessBasePtr;
		typedef CPostProcessBase::CPPTexManager::restex_array_t									restex_array_t;

	protected:
		CPostProcessBasePtr				_pPostProcess;
		IPostProcessPtr					_pAttachedPP;
		buffer< TPostProcessTexture >	_aSrcTextures;		// input
		uint							_uIndex;
		bool							_bMultiPass;

	protected:
		virtual void _OnAttachedFrom(IPostProcess *pPostProcess);

	public:
		CPostProcess(const CPostProcessBasePtr &);
		virtual ~CPostProcess();
		
		// IPostProcess //
		
		// input
		virtual bool GetInputTextures(pptex_types_array_t &aTexTypes) const;
		virtual bool InputTexture(const CTexturePtr &pTex, e_pp_texture::type eType);
		virtual bool InputTextures(const pptex_array_t &aTextures);
		virtual void ResetInputTextures();

		// output
		virtual bool GetOutputTextures(pptex_array_t &aTextures) const;
		
		// multipass
		virtual bool IsMultiProcess();
		virtual bool GetAttachedPostProcess(IPostProcessBasePtr &pPostProcess);
		virtual bool AttachToLast(const IPostProcessBasePtr &pPostProcess, uint uIndex);
		virtual bool AttachPostProcess(const IPostProcessBasePtr &pPostProcess, uint uIndex);
		virtual bool DetachPostProcess();

		virtual bool CheckStatus();
		virtual bool Process(uint uIndex, bool bToScreen);
		virtual uint GetMaxIndex();
		
		virtual bool GetPostProcess(IPostProcessBasePtr &pPostProcess);

		// CEngBaseObject //
		virtual void Release();
	};
	
//-------------------------------------------------------------------

}	// EngineResource
}	// Engine

#endif	// _UX_BASE_RESOURCE_H